/*
 * @Description: 目录树组件
 * @Author: Rfan
 * @Date: 2022-02-18 12:05:33
 * @LastEditTime: 2023-02-27 09:29:53
 */

import { Key, useEffect, useState } from 'react';
import { Tree } from 'antd';
import classNames from 'classnames/bind';
import { useContextMenu } from 'react-contexify';
import { FolderTreeContextProvider, useFolderTreeContext } from './contexts/FolderTreeContext';
import TopContextMenu from './components/TopContextMenu';
import NodeContextMenu from './components/NodeContextMenu';
import { MENU_ID, TOP_ID } from './constants';
import { fetchChildTreeNode } from '@/api/floderTree';
import type { IFolderTreeNode } from '@/interfaces/folderTree';

import 'react-contexify/dist/ReactContexify.min.css';
import styles from './styles/main.module.scss';
import { appState } from '@/store/mobx';

const cx = classNames.bind(styles);

const { TreeNode } = Tree;

export const findNodeById = (list: IFolderTreeNode[], nodeId: number): IFolderTreeNode | null => {
  // const _list = treeToArr(treeData);
  return list.find((node) => node.id === nodeId) || null;
};

/**
 * @description: 根据节点类型查询节点
 * @param {IFolderTreeNode} node 当前节点
 * @param {number} type 要查询的节点类型
 * @param {IFolderTreeNode[]} list 查询的树
 * @return {IFolderTreeNode} 找到的节点
 */
export const findTargetNodeByType = (
  node: IFolderTreeNode,
  type: number,
  list: IFolderTreeNode[]
): IFolderTreeNode => {
  if (node.nodeType === type) {
    return node;
  }
  if (node.pid) {
    const parentNode = findNodeById(list, node.pid);
    return parentNode && findTargetNodeByType(parentNode, type, list);
  }
  return node;
};

interface IFolderTreeProps {
  onChange: any;
}

const FolderTreeComp = (props: IFolderTreeProps) => {
  const { onChange } = props;
  const {
    treeData,
    setTreeData,
    flatTreeList,
    expandedKeys,
    selectedKeys,
    fetchRootNode,
    setExpandedKeys,
    setSelectKeys
  } = useFolderTreeContext();

  const [nodeType, setNodeType] = useState<string>('');

  useEffect(() => {
    const { unitId } = appState;

    if (appState.unitId) {
      fetchRootNode(unitId).then((res: any) => {
        if (res) {
          const { fondId, fondNodeId, nodeId, atItem } = res;
          setExpandedKeys([fondNodeId]);
          setSelectKeys([nodeId]);
          onChange({ nodeId, fondId, atItem, atId: atItem.id });
        }
      });
    }
  }, [appState.unitId]);

  /**
   * @description: 选中节点
   * @param {Key} selectedRowKeys 选中的key
   * @param {any} info 节点信息，包含传入的数据
   */
  const onSelect = (selectedRowKeys: Key[], info: any) => {
    if (info.node.dataNode) {
      setSelectKeys(selectedRowKeys);
      const { node } = info;
      const fondNode = findTargetNodeByType(node, 2, flatTreeList);
      const atNode = findTargetNodeByType(node, 3, flatTreeList);
      const fondId = fondNode?.businessId;
      const atId = atNode?.businessId;
      const levelList = atNode?.appContext ? JSON.parse(atNode.appContext) : undefined;
      const levelItem = levelList?.[0] || {};
      const atItem = {
        id: atId,
        atName: atNode.nodeName,
        atCode: levelItem.atCode,
        atType: levelItem.atType,
        atLevel: levelItem.level,
        levelList
      };
      onChange({ nodeId: node.id, fondId, atItem, atId });
    }
  };

  // --------- 绑定右键菜单 ----------------------------------------------------------------
  const { show } = useContextMenu();

  const onRightClick = ({ event, node }: any) => {
    console.log('right node', node);
    event.stopPropagation();
    setNodeType(node.type);
    if (!node.disabled) {
      show(event, { id: MENU_ID, props: node });
    }
  };

  const onOutsideRightClick = (evt: any) => {
    show(evt, { id: TOP_ID, props: { key: 'outside' } });
  };

  // 渲染树节点，主要目的是为了通过react-contexify包裹上下文菜单
  const renderEntityTreeNodes = (data: any) => {
    return data.map((item: any) => {
      if (item.children) {
        const result = (
          <TreeNode {...item} key={item.id}>
            {renderEntityTreeNodes(item.children)}
          </TreeNode>
        );

        return result;
      }

      return <TreeNode {...item} key={item.id} />;
    });
  };

  const updateTreeData = (list: any[], key: Key, children: any[]): any[] =>
    list.map((node) => {
      if (node.id === key) {
        return {
          ...node,
          children
        };
      }
      if (node.children) {
        return {
          ...node,
          children: updateTreeData(node.children, key, children)
        };
      }
      return node;
    });

  /**
   * @description: 动态加载树节点
   * @param {any} node
   */
  const onLoadData = (node: any) => {
    return new Promise<void>((resolve, reject) => {
      if (node.children) {
        resolve();
        return;
      }
      fetchChildTreeNode(node.id)
        .then((res) => {
          const { data } = res;
          setTreeData(
            updateTreeData(
              treeData,
              node.id,
              data.map((item: any) => ({
                ...item,
                isLeaf: item.leafNode
              }))
            )
          );
        })
        .finally(() => {
          resolve();
        });
    });
  };

  return (
    <div className={cx('folder-tree')} onContextMenu={onOutsideRightClick}>
      <Tree
        loadData={onLoadData}
        expandedKeys={expandedKeys}
        selectedKeys={selectedKeys}
        fieldNames={{ title: 'nodeName', key: 'id' }}
        onExpand={setExpandedKeys}
        onSelect={onSelect}
        onRightClick={onRightClick}
      >
        {renderEntityTreeNodes(treeData)}
      </Tree>
      <NodeContextMenu nodeType={nodeType} />
      <TopContextMenu />
    </div>
  );
};

const FolderTree = (props: IFolderTreeProps) => (
  <FolderTreeContextProvider>
    <FolderTreeComp {...props} />
  </FolderTreeContextProvider>
);

export default FolderTree;
